package com.wei.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wei.blog.common.constants.UserConstants;
import com.wei.blog.common.dto.Email;
import com.wei.blog.common.exception.BlogException;
import com.wei.blog.common.exception.EmailException;
import com.wei.blog.common.executor.ExecutorUtils;
import com.wei.blog.common.status.BlogStatus;
import com.wei.blog.common.utils.EmailUtils;
import com.wei.blog.common.utils.PasswordUtils;
import com.wei.blog.common.utils.UUIDUtils;
import com.wei.dao.UserDao;
import com.wei.entity.UserEntity;
import com.wei.service.UserService;
import com.wei.vo.UserToken;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.yaml.snakeyaml.events.Event;

import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/*处理业务*/
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {
    @Autowired
    private EmailUtils emailUtils;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    /**/
    @Override
    public void register(UserEntity userEntity) {
        /*判断当前邮箱是否被注册*/
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("email", userEntity.getEmail());
        UserEntity dbUserEntity = baseMapper.selectOne(queryWrapper);
        if (dbUserEntity != null)
            throw new EmailException("该邮箱已被注册");
        /*如果是没有被注册*/
        userEntity.setStatus(BlogStatus.USER_UN_ACTIVATE.getCode());

        /*设置激活码*/
        userEntity.setActiveCode(UUIDUtils.getUUid());
        /*设置激活日期*/
        userEntity.setCreateTime(new Date());
        /*设置密码*/
        userEntity.setPwd(PasswordUtils.encode(userEntity.getPwd()));
        /*向数据库中插入数据*/
        baseMapper.insert(userEntity);

        /*把信息保存在redis中*/
        stringRedisTemplate.opsForValue().set(
                //key
                String.format(UserConstants.ACTIVATEKEY, userEntity.getActiveCode()),
                //value
                userEntity.getId().toString(),
                //超时时间
                1,
                TimeUnit.DAYS);

        Email email = new Email();
        email.setTitle("这是Blog的激活邮件");
        email.setToUser(userEntity.getEmail());
        email.setContent("<a href ='http://127.0.0.1:8001/user/activateUser/"
                + userEntity.getActiveCode() + "'>点击</a>这里激活");

        ExecutorUtils.getExecutor().submit(() -> {
            emailUtils.sendEmail(email);
        });

    }

    @Override
    public void activateUser(String code) {
        /*找到用户，
         * 在redis中通过激活码找到用户*/
        String userId = stringRedisTemplate.opsForValue().get(
                String.format(UserConstants.ACTIVATEKEY, code)
        );

        /*判断userId是否为空*/
        if (ObjectUtils.isEmpty(userId)) {
            throw new BlogException("激活码错误");
        }

        /*修改用户信息，激活用户*/
        Integer i = baseMapper.updateUserStatus(BlogStatus.USER_ACTIVATE.getCode(), userId, code);

        /*删除redis信息*/
        stringRedisTemplate.delete(String.format(UserConstants.ACTIVATEKEY, code));

    }

    /*登录*/
    @Override
    public UserToken login(String username, String pwd) {
        //1、根据用户查询信息
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("username", username);
        UserEntity userEntity = baseMapper.selectOne(queryWrapper);
        //2、判断用户是否存在
        if (userEntity == null) {
            throw new BlogException("用户不存在");
        }
        //3、校验密码
        if (!PasswordUtils.checkpw(pwd, userEntity.getPwd())) {
            throw new BlogException("密码错误");
        }
        //4、检查是否激活
        if (userEntity.getStatus() != BlogStatus.USER_ACTIVATE.getCode()) {
            throw new BlogException("用户未激活");
        }
        //5、生成token
        UserToken userToken = new UserToken();
        /*设置登录时间*/
        userToken.setCreateTime(new Date());
        /*设置用户id*/
        userToken.setUid(userEntity.getId());
        /*设置用户名*/
        userToken.setUname(userEntity.getUsername());
        /*设置用户头像*/
        userToken.setHeadUrl(userEntity.getHeadUrl());
        /*生成token，复发且唯一*/
        userToken.setToken(UUIDUtils.getUUid());
        /*生成过期时间，获取当前时间戳*/
        long currentTime = System.currentTimeMillis();
        //设置默认超时时间
        long userDefaultTime = UserConstants.USER_DEFAULE_TIMEOUT * 1000;
        long userTtl = currentTime + userDefaultTime;
        Date ttl = new Date(userTtl);
        userToken.setTtl(ttl);
        //6、token一般存在redis中
        String key = String.format(UserConstants.USER_LOGIN_TOKEN, userToken.getToken());
        redisTemplate.opsForValue().set(
                key,
                userToken,
                userDefaultTime,
                TimeUnit.MILLISECONDS
        );

        return userToken;
    }

    @Override
    public void logout(String token) {
        //删除redis
        String key = String.format(UserConstants.USER_LOGIN_TOKEN, token);
        redisTemplate.delete(key);
    }

    @Override
    public void updatePassword(String oldPassword,
                               String newPassword,
                               String newPassword2,
                               UserToken userToken) {
        //判度变量是否为空
        if (oldPassword == null
                || oldPassword.equals("")
                || newPassword.equals("")
                || newPassword == null
                || newPassword2.equals("")
                || newPassword2 == null
        ) {
            throw new BlogException("参数错误！");
        }
        //旧密码与新密码比对
        if (!newPassword2.equals(newPassword)) {
            throw new BlogException("两次密码不一致");
        }
        //查询用户的完整信息（根据用户id）
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("id", userToken.getUid());
        UserEntity userEntity = baseMapper.selectOne(queryWrapper);
        //判断查询结果是否为空
        if (userEntity == null) {
            throw new BlogException("查询结果为空");
        }
        //旧密码与数据库密码比对
        if (!PasswordUtils.checkpw(oldPassword, userEntity.getPwd())) {
            throw new BlogException("密码错误！");
        }
        //比对成功则修改数据库中的密码
        userEntity.setPwd(PasswordUtils.encode(newPassword));
        int i = baseMapper.updateById(userEntity);
        if (i < 0) {
            throw new BlogException("修改失败");
        }
        //退出登录 删除redis
        String key = String.format(UserConstants.USER_LOGIN_TOKEN, userToken.getToken());
        redisTemplate.delete(key);
    }

    @Override
    public UserEntity findUserById(Integer uid) {
        //去redis里查询用户信息
        String key = String.format(UserConstants.USER_INFO_KEY, uid);
        UserEntity userEntity = (UserEntity) redisTemplate.opsForValue().get(key);
        //如果redis中没有该信息
        if (userEntity == null) {
            //加锁
            ReentrantLock lock = new ReentrantLock();
            try {
                //尝试获取资源
                boolean b = lock.tryLock();
                if (b) {
                    //如果拿到 业务只有一个人通过
                    userEntity = getById(uid);
                    if (userEntity == null) {
                        redisTemplate.opsForValue().set(key, null, 1, TimeUnit.DAYS);
                    } else {
                        redisTemplate.opsForValue().set(key, userEntity, 1, TimeUnit.DAYS);
                    }
                } else {
                    //如果没有拿到资源
                    Thread.sleep(500);
                    return findUserById(uid);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //解锁
                lock.unlock();
            }
        }

        //去mysql中查询 并将查询到的信息存入redis中

        return userEntity;
    }


}
